package dao;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

import entity.annotation.Manytoone;
import entity.annotation.Onetomany;
import entity.annotation.Onetoone;
import entity.annotation.Table;
import util.DBUtil;

public class BaseDao<T> {
	private Class<T> poclass;
	private String realTableName;

	@SuppressWarnings("unchecked")
	public BaseDao() {
		ParameterizedType pt = (ParameterizedType) this.getClass().getGenericSuperclass();
		poclass = (Class<T>) pt.getActualTypeArguments()[0];

		// 获取注解的表名
		Table tab = poclass.getAnnotation(Table.class);
		if (tab != null)
			realTableName = tab.name();
		else
			realTableName = poclass.getSimpleName();
		System.out.println(realTableName);
	}

	/*
	 * public void showFields(){ Field[] f=poclass.getDeclaredFields(); for(int
	 * i=0;i<f.length;i++){ System.out.println(f[i].getName()+"  "
	 * +f[i].getType().getSimpleName()); } }
	 */

	public void insert(T o) {
		StringBuffer sql = new StringBuffer("insert into ").append(realTableName).append("(");
		Field[] field = poclass.getDeclaredFields();
		int n = field.length;
		for (int i = 0; i < n; i++) {
			sql.append(field[i].getName());
			if (i < n - 1)
				sql.append(",");
			else
				sql.append(")");
		}
		sql.append(" values(");
		for (int i = 0; i < n; i++) {
			sql.append("?");
			if (i < n - 1)
				sql.append(",");
			else
				sql.append(")");
		}
		System.out.println(sql.toString());
		Connection con = DBUtil.getConnection();
		try {
			PreparedStatement pstm = con.prepareStatement(sql.toString());
			for (int i = 0; i < n; i++) {
				field[i].setAccessible(true);
				Object fieldValue = field[i].get(o);
				pstm.setObject(i + 1, fieldValue);
			}
			pstm.executeUpdate();
			con.close();

		} catch (SQLException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}

	}

	public T get(int id) {
		T o = null;
		try {
			Field[] field = poclass.getDeclaredFields();
			o = poclass.newInstance();
			String sql = "select * from t_" + poclass.getSimpleName() + "  where id=" + id;
			System.out.println(sql);
			Connection con = DBUtil.getConnection();
			Statement stm = con.createStatement();
			ResultSet rs = stm.executeQuery(sql);
			System.out.println(sql);
			int n = field.length;
			rs.next();
			for (int i = 0; i < n; i++) {
				field[i].setAccessible(true);
				Manytoone mto = field[i].getAnnotation(Manytoone.class);
				Onetomany otm = field[i].getAnnotation(Onetomany.class);
				Onetoone oto = field[i].getAnnotation(Onetoone.class);
				if (mto != null) {
					System.out.println(field[i].getName() + "被注解" + " " + mto.mappedby() + "  " + mto.mappedfk());
					System.out.println(rs.getObject(mto.mappedfk()));
					// select * from map.by where id=rs.getObject(map.fk)
					String mto_sql = "select * from t_" + mto.mappedby() + " where id=" + rs.getObject(mto.mappedfk());
					System.out.println(mto_sql);
					Object byo = field[i].getType().newInstance();
					Field[] by = field[i].getType().getDeclaredFields();// 通过判断设置注释已知哪个字段为外键，并获取外键所属表下的所有字段
					Connection f_con = DBUtil.getConnection();
					Statement f_stm = f_con.createStatement();
					ResultSet f_rs = f_stm.executeQuery(mto_sql);
					f_rs.next();
					for (int j = 0; j < by.length; j++) {
						System.out.println(by[j].getName());// 输出这些字段
						by[j].setAccessible(true);
						by[j].set(byo, f_rs.getObject(j + 1));// 将字段存入byo内
					}

					field[i].set(o, byo);// 将byo存入o以便调用
				}
				if (otm != null) {
					System.out.println(field[i].getName() + "被注解" + " " + otm.mappedby() + "  " + otm.mappedfk());
					String otm_sql = "select * from t_" + otm.mappedby() + " where " + otm.mappedfk() + "=" + id;
					System.out.println("otm==>" + otm_sql);
					// Object otm_o=field[i].getType().newInstance();
					List<Object> otm_list = new ArrayList<>();
					ParameterizedType pt = (ParameterizedType) field[i].getGenericType();
					Class tp = (Class) pt.getActualTypeArguments()[0];
					System.out.println("======>" + tp);
					Field[] otm_field = tp.getDeclaredFields();
					Connection otm_con = DBUtil.getConnection();
					Statement otm_stm = otm_con.createStatement();
					ResultSet otm_rs = otm_stm.executeQuery(otm_sql);
					while (otm_rs.next()) {
						Object ooo = tp.newInstance();
						for (int k = 0; k < otm_field.length; k++) {
							System.out.println(otm_field[k].getName());
							otm_field[k].setAccessible(true);
							if (otm_field[k].getAnnotations().length < 1)
								otm_field[k].set(ooo, otm_rs.getObject(k + 1));

						}
						otm_list.add(ooo);
					}
					field[i].set(o, otm_list);
				} else {
					field[i].set(o, rs.getObject(i + 1));
				}
			}
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return o;
	}

	private ResultSet getMapped(Field[] field, String sql) {
		return null;

	}

	public void delete(T o) {
		StringBuffer sql = new StringBuffer("delete from t_").append(poclass.getSimpleName()).append(" where id=")
				.append("?");
		Connection con = DBUtil.getConnection();
		Field field = poclass.getDeclaredFields()[0];
		try {
			PreparedStatement pst = con.prepareStatement(sql.toString());
			field.setAccessible(true);
			Object fieldValue = field.get(o);
			pst.setObject(1, fieldValue);
			pst.executeUpdate();
			con.close();
		} catch (SQLException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
	}

	// update t_user set name=?,role=? where id=?
	public void update(T o) {
		StringBuffer sql = new StringBuffer("update t_").append(poclass.getSimpleName()).append(" set ");
		Field[] field = poclass.getDeclaredFields();
		int n = field.length;
		try {
			for (int i = 1; i < n; i++) {
				sql.append(field[i].getName()).append("=?");
				if (i < n - 1)
					sql.append(",");
				else
					sql.append(" where id=?");
			}
			System.out.println(sql.toString());
			Connection con = DBUtil.getConnection();
			PreparedStatement pst = con.prepareStatement(sql.toString());
			for (int i = 1; i < n; i++) {
				field[i].setAccessible(true);
				Object fieldValue = field[i].get(o);
				pst.setObject(i, fieldValue);
			}
			field[0].setAccessible(true);
			pst.setObject(n, field[0].get(o));
			pst.executeUpdate();
			con.close();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
	}

	public List<T> getAll() {
		List<T> list = new ArrayList<>();
		// ------------
		StringBuffer sql = new StringBuffer("select * from t_").append(poclass.getSimpleName());
		Field[] field = poclass.getDeclaredFields();
		Connection con = DBUtil.getConnection();
		try {
			Statement st = con.createStatement();
			ResultSet rs = st.executeQuery(sql.toString());
			int n = field.length;
			while (rs.next()) {
				T o = poclass.newInstance();
				for (int i = 0; i < n; i++) {
					field[i].setAccessible(true);
					field[i].set(o, rs.getObject(i + 1));
				}
				list.add(o);
			}

		} catch (SQLException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		return list;
	}

	public List<T> find(T o) {
		List<T> list = new ArrayList<>();
		StringBuffer sql = new StringBuffer("select * from t_").append(poclass.getSimpleName()).append(" where ");
		Field[] fields = poclass.getDeclaredFields();
		int n = fields.length;
		Boolean isFirst = true;
		try {
			for (int i = 0; i < n; i++) {
				fields[i].setAccessible(true);
				Object fieldvalue = fields[i].get(o);
				if (fieldvalue != null) {
					if (isFirst) {
						isFirst = false;
					} else {
						sql.append(" and ");
					}
					sql.append(fields[i].getName()).append("='").append(fieldvalue).append("' ");
				}
			}
			System.out.println(sql.toString());
			Connection con = DBUtil.getConnection();
			PreparedStatement pst = con.prepareStatement(sql.toString());
			Statement stm = con.createStatement();
			ResultSet rs = stm.executeQuery(sql.toString());
			while (rs.next()) {
				T oo = poclass.newInstance();
				for (int i = 0; i < n; i++) {
					fields[i].setAccessible(true);
					fields[i].set(oo, rs.getObject(i + 1));
				}
				list.add(oo);
			}

		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		}
		return list;
	}
}
